class VideoService {
    constructor(channels, charge) {
        this.channels = channels;
        this.charge = charge;
        this.users = [];

        console.log(`[Video Service]`);
        console.log(
            `[Video Service] channels: ${JSON.stringify(this.channels)}`
        );
        console.log(`[Video Service] charge: ${JSON.stringify(this.charge)}`);
    }

    /**
     * 登记通道
     */
    allocateChannel = (time, userId, videoType) => {
        let channel = this.findChannel(videoType);
        if (channel === null) {
            return false;
        }

        // 登记用户
        let user = this.users.find((usr) => usr.id === userId);
        if (!!user) {
            // 如果当前已经存在该用户，先释放这个用户的所在渠道
            this.freeChannel(time, userId);
        }

        let newUser = {
            id: userId,
            time: time,
            applyType: videoType,
            actType: channel,
        };

        this.users.push(newUser);

        this.channels[channel] = this.channels[channel] - 1;

        console.log(
            `[allocateChannel success] channels: ${JSON.stringify(
                this.channels
            )}`
        );

        console.log(
            `[allocateChannel success] channels: ${JSON.stringify(newUser)}`
        );

        return true;
    };

    findChannel = (videoType) => {
        let available = this.channels[videoType];

        if (available > 0) {
            return videoType;
        }

        if (videoType === 2) {
            return null;
        }

        return this.findChannel(videoType + 1);
    };

    freeChannel = (time, userId) => {
        let userIndex = this.users.findIndex((usr) => usr.id === userId);
        if (userIndex < 0) {
            return 0;
        }

        let user = this.users[userIndex];

        // 释放通道
        let channelType = user.actType;
        this.channels[channelType] = this.channels[channelType] + 1;

        // 循环降级现有用户通道
        this.degradeChannel(channelType);

        let fee = (time - user.time) * this.charge[user.applyType]; // 计算支出

        // 删除用户
        this.users.splice(userIndex, 1);

        return fee;
    };

    degradeChannel = (channelType) => {
        let users = this.users.filter(
            (user) =>
                user.actType > user.applyType &&
                user.actType > channelType &&
                user.applyType <= channelType
        );

        if (users.length <= 0) return;

        // 排序
        // 渠道等级高的排在前面
        // 相同渠道等级的，id小的排在前面
        users.sort((a, b) => {
            if (a.actType > b.actType) {
                return -1;
            }

            if (a.actType < b.actType) {
                return 1;
            }

            return a.id - b.id;
        });

        let user = users[0];
        let currentChannel = user.actType;
        user.actType = channelType;
        this.channels[channelType] = this.channels[channelType] - 1;
        this.channels[currentChannel] = this.channels[currentChannel] + 1;

        console.log(
            `用户通道降级 userid: ${user.id}, 原通道： ${currentChannel} => 新通道 ${channelType}`
        );

        console.log(`通道情况: ${JSON.stringify(this.channels)}`);

        this.degradeChannel(currentChannel);
    };

    queryChannel = (userId) => {
        let user = this.users.find((usr) => usr.id === userId);
        return !user ? -1 : user.actType;
    };
}

function t(cb) {
    console.log(`output >> ${JSON.stringify(cb)} `);
}

let vs = new VideoService([1, 1, 2], [5, 10, 20]); // null;
t(vs.allocateChannel(1, 100, 0)); // true
t(vs.allocateChannel(1, 101, 0)); // true
t(vs.allocateChannel(2, 102, 0)); // true
t(vs.allocateChannel(4, 103, 0)); // true
t(vs.freeChannel(6, 100)); // 25
t(vs.queryChannel(102)); // 0
t(vs.freeChannel(7, 103)); // 15
t(vs.allocateChannel(7, 104, 1)); // true
t(vs.freeChannel(8, 102)); // 30
t(vs.queryChannel(104)); // 1
